﻿using System;
using System.Collections.Generic;
using System.Windows.Media.Imaging;

namespace ImageProcessing
{
    public static class GradientOperations
    {
        public static EventHandler<ProgressValueEventArgs> ProgressChangeEventHandler;
        const int Plen = 4;
        // РАЗНОСТНЫЙ  градиентный  оператор. Квадратный корень.
        public static void DifferenceSquareRoot(WriteableBitmap image)
        {
            var pixels = new byte[image.PixelHeight * image.BackBufferStride];
            var pixelsResult = new byte[image.PixelHeight * image.BackBufferStride];
            image.CopyPixels(pixels, image.BackBufferStride, 0);
            image.CopyPixels(pixelsResult, image.BackBufferStride, 0);
            for (var i =0; i < image.PixelHeight-1; i++)
            {
                var handler = ProgressChangeEventHandler;
                if (handler != null)
                    handler(null, new ProgressValueEventArgs((double)i / (double)(image.PixelHeight -1)));
                for (var j = 0; j < image.PixelWidth-1; j++)
                {
                    var r1 = ((pixels[i * image.PixelWidth * Plen + j * Plen] - pixels[i * image.PixelWidth * Plen + (j+1) * Plen])
                           + (pixels[(i+1) * image.PixelWidth * Plen + j * Plen] - pixels[(i+1) * image.PixelWidth * Plen + (j + 1) * Plen]));
                    r1 *= r1;
                    var r2 = ((pixels[i * image.PixelWidth * Plen + j * Plen] - pixels[(i+1) * image.PixelWidth * Plen + j  * Plen])
                           + (pixels[i * image.PixelWidth * Plen + (j+1) * Plen] - pixels[(i + 1) * image.PixelWidth * Plen + (j + 1) * Plen]));
                    r2*=r2;
                    pixelsResult[i * image.PixelWidth * Plen + j * Plen] = (byte)Math.Max(0, Math.Min(255, Math.Sqrt(r1 + r2)));

                    var g1 = ((pixels[i * image.PixelWidth * Plen + j * Plen+1] - pixels[i * image.PixelWidth * Plen + (j + 1) * Plen+1])
                           + (pixels[(i + 1) * image.PixelWidth * Plen + j * Plen +1 ] - pixels[(i + 1) * image.PixelWidth * Plen + (j + 1) * Plen +1]));
                    g1 *= g1;
                    var g2 = ((pixels[i * image.PixelWidth * Plen + j * Plen +1] - pixels[(i + 1) * image.PixelWidth * Plen + j * Plen +1])
                           + (pixels[i * image.PixelWidth * Plen + (j + 1) * Plen +1] - pixels[(i + 1) * image.PixelWidth * Plen + (j + 1) * Plen +1]));
                    g2 *= g2;
                    pixelsResult[i * image.PixelWidth * Plen + j * Plen + 1] = (byte)Math.Max(0, Math.Min(255, Math.Sqrt(g1 + g2)));

                    var b1 = ((pixels[i * image.PixelWidth * Plen + j * Plen + 2] - pixels[i * image.PixelWidth * Plen + (j + 1) * Plen + 2])
                         + (pixels[(i + 1) * image.PixelWidth * Plen + j * Plen + 2] - pixels[(i + 1) * image.PixelWidth * Plen + (j + 1) * Plen + 2]));
                    b1 *= b1;
                    var b2 = ((pixels[i * image.PixelWidth * Plen + j * Plen + 2] - pixels[(i + 1) * image.PixelWidth * Plen + j * Plen + 2])
                           + (pixels[i * image.PixelWidth * Plen + (j + 1) * Plen + 2] - pixels[(i + 1) * image.PixelWidth * Plen + (j + 1) * Plen + 2]));
                    b2 *= b2;
                    pixelsResult[i * image.PixelWidth * Plen + j * Plen + 2] = (byte)Math.Max(0, Math.Min(255, Math.Sqrt(b1 + b2)));
                }
            }
            image.WritePixels(new System.Windows.Int32Rect(0, 0, image.PixelWidth, image.PixelHeight), pixelsResult,
                              image.BackBufferStride, 0);
            var handler_ = ProgressChangeEventHandler;
            if (handler_ != null)
                handler_(null, new ProgressValueEventArgs(0));
        }


        // РАЗНОСТНЫЙ  градиентный  оператор. Модуль.
        public static void DifferenceModule(WriteableBitmap image)
        {
            var pixels = new byte[image.PixelHeight * image.BackBufferStride];
            var pixelsResult = new byte[image.PixelHeight * image.BackBufferStride];
            image.CopyPixels(pixels, image.BackBufferStride, 0);
            image.CopyPixels(pixelsResult, image.BackBufferStride, 0);
            for (var i = 0; i < image.PixelHeight-1; i++)
            {
                var handler = ProgressChangeEventHandler;
                if (handler != null)
                    handler(null, new ProgressValueEventArgs((double)i / (double)(image.PixelHeight - 1)));
                for (var j = 0; j < image.PixelWidth-1; j++)
                {
                    var r1 = ((pixels[i * image.PixelWidth * Plen + j * Plen] - pixels[i * image.PixelWidth * Plen + (j + 1) * Plen])
                           + (pixels[(i + 1) * image.PixelWidth * Plen + j * Plen] - pixels[(i + 1) * image.PixelWidth * Plen + (j + 1) * Plen]));
                    r1 = Math.Sign(r1)*r1;
                    var r2 = ((pixels[i * image.PixelWidth * Plen + j * Plen] - pixels[(i + 1) * image.PixelWidth * Plen + j * Plen])
                           + (pixels[i * image.PixelWidth * Plen + (j + 1) * Plen] - pixels[(i + 1) * image.PixelWidth * Plen + (j + 1) * Plen]));
                    r2 =  Math.Sign(r2)*r2;
                    pixelsResult[i * image.PixelWidth * Plen + j * Plen] = (byte)Math.Max(0, Math.Min(255, r1 + r2));

                    var g1 = ((pixels[i * image.PixelWidth * Plen + j * Plen + 1] - pixels[i * image.PixelWidth * Plen + (j + 1) * Plen + 1])
                           + (pixels[(i + 1) * image.PixelWidth * Plen + j * Plen + 1] - pixels[(i + 1) * image.PixelWidth * Plen + (j + 1) * Plen + 1]));
                    g1 = Math.Sign(g1) * g1;
                    var g2 = ((pixels[i * image.PixelWidth * Plen + j * Plen + 1] - pixels[(i + 1) * image.PixelWidth * Plen + j * Plen + 1])
                           + (pixels[i * image.PixelWidth * Plen + (j + 1) * Plen + 1] - pixels[(i + 1) * image.PixelWidth * Plen + (j + 1) * Plen + 1]));
                    g2 = Math.Sign(g2) * g2;
                    pixelsResult[i * image.PixelWidth * Plen + j * Plen + 1] = (byte)Math.Max(0, Math.Min(255, g1 + g2));

                    var b1 = ((pixels[i * image.PixelWidth * Plen + j * Plen + 2] - pixels[i * image.PixelWidth * Plen + (j + 1) * Plen + 2])
                         + (pixels[(i + 1) * image.PixelWidth * Plen + j * Plen + 2] - pixels[(i + 1) * image.PixelWidth * Plen + (j + 1) * Plen + 2]));
                    b1 = Math.Sign(b1) * b1;
                    var b2 = ((pixels[i * image.PixelWidth * Plen + j * Plen + 2] - pixels[(i + 1) * image.PixelWidth * Plen + j * Plen + 2])
                           + (pixels[i * image.PixelWidth * Plen + (j + 1) * Plen + 2] - pixels[(i + 1) * image.PixelWidth * Plen + (j + 1) * Plen + 2]));
                    b2 = Math.Sign(b2) * b2;
                    pixelsResult[i * image.PixelWidth * Plen + j * Plen + 2] = (byte)Math.Max(0, Math.Min(255, b1 + b2));
                }
            }
            image.WritePixels(new System.Windows.Int32Rect(0, 0, image.PixelWidth, image.PixelHeight), pixelsResult,
                              image.BackBufferStride, 0);
            var handler_ = ProgressChangeEventHandler;
            if (handler_ != null)
                handler_(null, new ProgressValueEventArgs(0));
        }

        // РАЗНОСТНЫЙ  градиентный  оператор. Максимальная разность.
        public static void MaxDifference(WriteableBitmap image)
        {
            var pixels = new byte[image.PixelHeight * image.BackBufferStride];
            var pixelsResult = new byte[image.PixelHeight * image.BackBufferStride];
            image.CopyPixels(pixels, image.BackBufferStride, 0);
            image.CopyPixels(pixelsResult, image.BackBufferStride, 0);
            for (var i = 0; i < image.PixelHeight - 1; i++)
            {
                var handler = ProgressChangeEventHandler;
                if (handler != null)
                    handler(null, new ProgressValueEventArgs((double)i / (double)(image.PixelHeight - 1)));
                for (var j = 0; j < image.PixelWidth - 1; j++)
                {
                    var list = new List<Pixel>();
                    list.Add(new Pixel(pixels[i * image.PixelWidth * Plen + j * Plen],pixels[i * image.PixelWidth * Plen + j * Plen +1 ],
                        pixels[i * image.PixelWidth * Plen + j * Plen + 2], pixels[i * image.PixelWidth * Plen + j * Plen + 3]));
                    list.Add(new Pixel(pixels[(i + 1) * image.PixelWidth * Plen + j * Plen], pixels[(i + 1) * image.PixelWidth * Plen + j * Plen + 1],
                        pixels[(i + 1) * image.PixelWidth * Plen + j * Plen + 2], pixels[(i + 1) * image.PixelWidth * Plen + j * Plen + 3]));
                    list.Add(new Pixel(pixels[i * image.PixelWidth * Plen + (j + 1) * Plen], pixels[i * image.PixelWidth * Plen + (j + 1) * Plen + 1],
                       pixels[i * image.PixelWidth * Plen + (j + 1) * Plen + 2], pixels[i * image.PixelWidth * Plen + (j + 1) * Plen + 3]));
                    list.Add(new Pixel(pixels[(i + 1) * image.PixelWidth * Plen + (j + 1) * Plen], pixels[(i + 1) * image.PixelWidth * Plen + (j + 1) * Plen + 1],
                        pixels[(i + 1) * image.PixelWidth * Plen + (j + 1) * Plen + 2], pixels[(i + 1) * image.PixelWidth * Plen + (j + 1) * Plen + 3]));
                   list.Sort();
                    pixelsResult[i * image.PixelWidth*Plen + j*Plen] = (byte) Math.Max(0, list[3].r - list[0].r);
                    pixelsResult[i * image.PixelWidth * Plen + j * Plen +1] = (byte)Math.Max(0, list[3].g - list[0].g);
                    pixelsResult[i * image.PixelWidth * Plen + j * Plen+ 2] = (byte)Math.Max(0, list[3].b - list[0].b);
                }
            }
            image.WritePixels(new System.Windows.Int32Rect(0, 0, image.PixelWidth, image.PixelHeight), pixelsResult,
                              image.BackBufferStride, 0);
            var handler_ = ProgressChangeEventHandler;
            if (handler_ != null)
                handler_(null, new ProgressValueEventArgs(0));
        }


        // Робертс. Квадратный корень.
        public static void RobertsSquareRoot(WriteableBitmap image)
        {
            var pixels = new byte[image.PixelHeight * image.BackBufferStride];
            var pixelsResult = new byte[image.PixelHeight * image.BackBufferStride];
            image.CopyPixels(pixels, image.BackBufferStride, 0);
            image.CopyPixels(pixelsResult, image.BackBufferStride, 0);
            for (var i = 0; i < image.PixelHeight - 1; i++)
            {
                var handler = ProgressChangeEventHandler;
                if (handler != null)
                    handler(null, new ProgressValueEventArgs((double)i / (double)(image.PixelHeight - 1)));
                for (var j = 0; j < image.PixelWidth - 1; j++)
                {
                    var r1 = (pixels[i*image.PixelWidth*Plen + j*Plen] - pixels[(i + 1)*image.PixelWidth*Plen + (j + 1)*Plen]);
                    r1 *= r1;
                    var r2 = (pixels[(i+1)*image.PixelWidth*Plen + j*Plen] - pixels[i*image.PixelWidth*Plen + (j+1)*Plen]);
                    r2 *= r2;
                    pixelsResult[i * image.PixelWidth * Plen + j * Plen] = (byte)Math.Max(0, Math.Min(255, Math.Sqrt(r1 + r2)));

                    var g1 = (pixels[i * image.PixelWidth * Plen + j * Plen+1] - pixels[(i + 1) * image.PixelWidth * Plen + (j + 1) * Plen+1]);
                    g1 *= g1;
                    var g2 = (pixels[(i + 1) * image.PixelWidth * Plen + j * Plen+1] - pixels[i * image.PixelWidth * Plen + (j + 1) * Plen+1]);
                    g2 *= g2;
                    pixelsResult[i * image.PixelWidth * Plen + j * Plen+1] = (byte)Math.Max(0, Math.Min(255, Math.Sqrt(g1 + g2)));

                    var b1 = (pixels[i * image.PixelWidth * Plen + j * Plen+2] - pixels[(i + 1) * image.PixelWidth * Plen + (j + 1) * Plen+2]);
                    b1 *= b1;
                    var b2 = (pixels[(i + 1) * image.PixelWidth * Plen + j * Plen+2] - pixels[i * image.PixelWidth * Plen + (j + 1) * Plen+2]);
                    b2 *= b2;
                    pixelsResult[i * image.PixelWidth * Plen + j * Plen+2] = (byte)Math.Max(0, Math.Min(255, Math.Sqrt(b1 + b2)));


                }
            }
            image.WritePixels(new System.Windows.Int32Rect(0, 0, image.PixelWidth, image.PixelHeight), pixelsResult,
                              image.BackBufferStride, 0);
            var handler_ = ProgressChangeEventHandler;
            if (handler_ != null)
                handler_(null, new ProgressValueEventArgs(0));
        }


        // Робертс. Модуль.
        public static void RobertsModule(WriteableBitmap image)
        {
            var pixels = new byte[image.PixelHeight * image.BackBufferStride];
            var pixelsResult = new byte[image.PixelHeight * image.BackBufferStride];
            image.CopyPixels(pixels, image.BackBufferStride, 0);
            image.CopyPixels(pixelsResult, image.BackBufferStride, 0);
            for (var i = 0; i < image.PixelHeight - 1; i++)
            {
                var handler = ProgressChangeEventHandler;
                if (handler != null)
                    handler(null, new ProgressValueEventArgs((double)i / (double)(image.PixelHeight -1)));
                for (var j = 0; j < image.PixelWidth - 1; j++)
                {
                    var r1 = (pixels[i * image.PixelWidth * Plen + j * Plen] - pixels[(i + 1) * image.PixelWidth * Plen + (j + 1) * Plen]);
                    r1 *=Math.Sign(r1);
                    var r2 = (pixels[(i + 1) * image.PixelWidth * Plen + j * Plen] - pixels[i * image.PixelWidth * Plen + (j + 1) * Plen]);
                    r2 *= Math.Sign(r2);
                    pixelsResult[i * image.PixelWidth * Plen + j * Plen] = (byte)Math.Max(0, Math.Min(255, r1 + r2));

                    var g1 = (pixels[i * image.PixelWidth * Plen + j * Plen + 1] - pixels[(i + 1) * image.PixelWidth * Plen + (j + 1) * Plen + 1]);
                    g1 *= Math.Sign(g1);
                    var g2 = (pixels[(i + 1) * image.PixelWidth * Plen + j * Plen + 1] - pixels[i * image.PixelWidth * Plen + (j + 1) * Plen + 1]);
                    g2 *= Math.Sign(g2);
                    pixelsResult[i * image.PixelWidth * Plen + j * Plen + 1] = (byte)Math.Max(0, Math.Min(255, g1 + g2));

                    var b1 = (pixels[i * image.PixelWidth * Plen + j * Plen + 2] - pixels[(i + 1) * image.PixelWidth * Plen + (j + 1) * Plen + 2]);
                    b1 *= Math.Sign(b1);
                    var b2 = (pixels[(i + 1) * image.PixelWidth * Plen + j * Plen + 2] - pixels[i * image.PixelWidth * Plen + (j + 1) * Plen + 2]);
                    b2 *= Math.Sign(b2);
                    pixelsResult[i * image.PixelWidth * Plen + j * Plen + 2] = (byte)Math.Max(0, Math.Min(255, b1 + b2));
                }
            }
            image.WritePixels(new System.Windows.Int32Rect(0, 0, image.PixelWidth, image.PixelHeight), pixelsResult,
                              image.BackBufferStride, 0);
                               var handler_ = ProgressChangeEventHandler;
            if (handler_ != null)
                handler_(null, new ProgressValueEventArgs(0));
        }

        // Превитт. Квадратный корень.
        public static void PrevittSquareRoot(WriteableBitmap image)
        {
            var pixels = new byte[image.PixelHeight * image.BackBufferStride];
            var pixelsResult = new byte[image.PixelHeight * image.BackBufferStride];
            image.CopyPixels(pixels, image.BackBufferStride, 0);
            image.CopyPixels(pixelsResult, image.BackBufferStride, 0);
            for (var i = 0; i < image.PixelHeight - 2; i++)
            {
                var handler = ProgressChangeEventHandler;
                if (handler != null)
                    handler(null, new ProgressValueEventArgs((double)i / (double)(image.PixelHeight - 1)));
                for (var j = 0; j < image.PixelWidth - 2; j++)
                {
                    var r1 = pixels[i*image.PixelWidth*Plen + j*Plen] - pixels[i*image.PixelWidth*Plen + (j + 2)*Plen] +
                             pixels[(i + 1)*image.PixelWidth*Plen + j*Plen] - pixels[(i + 1)*image.PixelWidth*Plen + (j + 2)*Plen] +
                             pixels[(i + 2)*image.PixelWidth*Plen + j*Plen] - pixels[(i + 2)*image.PixelWidth*Plen + (j + 2)*Plen];
                    r1 *= r1;
                    var r2 = pixels[i * image.PixelWidth * Plen + j * Plen] - pixels[(i+2) * image.PixelWidth * Plen + j * Plen] +
                             pixels[i  * image.PixelWidth * Plen + (j+1) * Plen] - pixels[(i + 2) * image.PixelWidth * Plen + (j + 1) * Plen] +
                             pixels[i * image.PixelWidth * Plen + (j+2) * Plen] - pixels[(i + 2) * image.PixelWidth * Plen + (j + 2) * Plen];
                    r2 *= r2;
                    pixelsResult[i * image.PixelWidth * Plen + j * Plen] = (byte)Math.Max(0, Math.Min(255, Math.Sqrt(r1 + r2)));

                    var g1 = pixels[i * image.PixelWidth * Plen + j * Plen + 1] - pixels[i * image.PixelWidth * Plen + (j + 2) * Plen + 1] +
                             pixels[(i + 1) * image.PixelWidth * Plen + j * Plen + 1] - pixels[(i + 1) * image.PixelWidth * Plen + (j + 2) * Plen + 1] +
                             pixels[(i + 2) * image.PixelWidth * Plen + j * Plen + 1] - pixels[(i + 2) * image.PixelWidth * Plen + (j + 2) * Plen + 1];
                    g1 *= g1;
                    var g2 = pixels[i * image.PixelWidth * Plen + j * Plen + 1] - pixels[(i + 2) * image.PixelWidth * Plen + j * Plen + 1] +
                             pixels[i * image.PixelWidth * Plen + (j + 1) * Plen + 1] - pixels[(i + 2) * image.PixelWidth * Plen + (j + 1) * Plen + 1] +
                             pixels[i * image.PixelWidth * Plen + (j + 2) * Plen + 1] - pixels[(i + 2) * image.PixelWidth * Plen + (j + 2) * Plen + 1];
                    g2 *= g2;
                    pixelsResult[i * image.PixelWidth * Plen + j * Plen+1] = (byte)Math.Max(0, Math.Min(255, Math.Sqrt(g1 + g2)));

                    var b1 = pixels[i * image.PixelWidth * Plen + j * Plen + 2] - pixels[i * image.PixelWidth * Plen + (j + 2) * Plen + 2] +
                             pixels[(i + 1) * image.PixelWidth * Plen + j * Plen + 2] - pixels[(i + 1) * image.PixelWidth * Plen + (j + 2) * Plen + 2] +
                             pixels[(i + 2) * image.PixelWidth * Plen + j * Plen + 2] - pixels[(i + 2) * image.PixelWidth * Plen + (j + 2) * Plen + 2];
                    b1 *= b1;
                    var b2 = pixels[i * image.PixelWidth * Plen + j * Plen + 2] - pixels[(i + 2) * image.PixelWidth * Plen + j * Plen + 2] +
                             pixels[i * image.PixelWidth * Plen + (j + 1) * Plen + 2] - pixels[(i + 2) * image.PixelWidth * Plen + (j + 1) * Plen + 2] +
                             pixels[i * image.PixelWidth * Plen + (j + 2) * Plen + 2] - pixels[(i + 2) * image.PixelWidth * Plen + (j + 2) * Plen + 2];
                    b2 *= b2;
                    pixelsResult[i * image.PixelWidth * Plen + j * Plen + 2] = (byte)Math.Max(0, Math.Min(255, Math.Sqrt(b1 + b2)));
                }
            }
            image.WritePixels(new System.Windows.Int32Rect(0, 0, image.PixelWidth, image.PixelHeight), pixelsResult,
                              image.BackBufferStride, 0);
            var handler_ = ProgressChangeEventHandler;
            if (handler_ != null)
                handler_(null, new ProgressValueEventArgs(0));
        }

        // Превитт. Модуль.
        public static void PrevittModule(WriteableBitmap image)
        {
            var pixels = new byte[image.PixelHeight * image.BackBufferStride];
            var pixelsResult = new byte[image.PixelHeight * image.BackBufferStride];
            image.CopyPixels(pixels, image.BackBufferStride, 0);
            image.CopyPixels(pixelsResult, image.BackBufferStride, 0);
            for (var i = 0; i < image.PixelHeight - 2; i++)
            {
                var handler = ProgressChangeEventHandler;
                if (handler != null)
                    handler(null, new ProgressValueEventArgs((double)i / (double)(image.PixelHeight - 1)));
                for (var j = 0; j < image.PixelWidth - 2; j++)
                {
                    var r1 = pixels[i * image.PixelWidth * Plen + j * Plen] - pixels[i * image.PixelWidth * Plen + (j + 2) * Plen] +
                             pixels[(i + 1) * image.PixelWidth * Plen + j * Plen] - pixels[(i + 1) * image.PixelWidth * Plen + (j + 2) * Plen] +
                             pixels[(i + 2) * image.PixelWidth * Plen + j * Plen] - pixels[(i + 2) * image.PixelWidth * Plen + (j + 2) * Plen];
                    r1 *= Math.Sign(r1);
                    var r2 = pixels[i * image.PixelWidth * Plen + j * Plen] - pixels[(i + 2) * image.PixelWidth * Plen + j * Plen] +
                             pixels[i * image.PixelWidth * Plen + (j + 1) * Plen] - pixels[(i + 2) * image.PixelWidth * Plen + (j + 1) * Plen] +
                             pixels[i * image.PixelWidth * Plen + (j + 2) * Plen] - pixels[(i + 2) * image.PixelWidth * Plen + (j + 2) * Plen];
                    r2 *= Math.Sign(r2);
                    pixelsResult[i * image.PixelWidth * Plen + j * Plen] = (byte)Math.Max(0, Math.Min(255, Math.Sqrt(r1 + r2)));

                    var g1 = pixels[i * image.PixelWidth * Plen + j * Plen + 1] - pixels[i * image.PixelWidth * Plen + (j + 2) * Plen + 1] +
                             pixels[(i + 1) * image.PixelWidth * Plen + j * Plen + 1] - pixels[(i + 1) * image.PixelWidth * Plen + (j + 2) * Plen + 1] +
                             pixels[(i + 2) * image.PixelWidth * Plen + j * Plen + 1] - pixels[(i + 2) * image.PixelWidth * Plen + (j + 2) * Plen + 1];
                    g1 *= Math.Sign(g1);
                    var g2 = pixels[i * image.PixelWidth * Plen + j * Plen + 1] - pixels[(i + 2) * image.PixelWidth * Plen + j * Plen + 1] +
                             pixels[i * image.PixelWidth * Plen + (j + 1) * Plen + 1] - pixels[(i + 2) * image.PixelWidth * Plen + (j + 1) * Plen + 1] +
                             pixels[i * image.PixelWidth * Plen + (j + 2) * Plen + 1] - pixels[(i + 2) * image.PixelWidth * Plen + (j + 2) * Plen + 1];
                    g2 *= Math.Sign(g2);
                    pixelsResult[i * image.PixelWidth * Plen + j * Plen + 1] = (byte)Math.Max(0, Math.Min(255, Math.Sqrt(g1 + g2)));

                    var b1 = pixels[i * image.PixelWidth * Plen + j * Plen + 2] - pixels[i * image.PixelWidth * Plen + (j + 2) * Plen + 2] +
                             pixels[(i + 1) * image.PixelWidth * Plen + j * Plen + 2] - pixels[(i + 1) * image.PixelWidth * Plen + (j + 2) * Plen + 2] +
                             pixels[(i + 2) * image.PixelWidth * Plen + j * Plen + 2] - pixels[(i + 2) * image.PixelWidth * Plen + (j + 2) * Plen + 2];
                    b1 *= Math.Sign(b1);
                    var b2 = pixels[i * image.PixelWidth * Plen + j * Plen + 2] - pixels[(i + 2) * image.PixelWidth * Plen + j * Plen + 2] +
                             pixels[i * image.PixelWidth * Plen + (j + 1) * Plen + 2] - pixels[(i + 2) * image.PixelWidth * Plen + (j + 1) * Plen + 2] +
                             pixels[i * image.PixelWidth * Plen + (j + 2) * Plen + 2] - pixels[(i + 2) * image.PixelWidth * Plen + (j + 2) * Plen + 2];
                    b2 *= Math.Sign(b2);
                    pixelsResult[i * image.PixelWidth * Plen + j * Plen + 2] = (byte)Math.Max(0, Math.Min(255, Math.Sqrt(b1 + b2)));
                }
            }
            image.WritePixels(new System.Windows.Int32Rect(0, 0, image.PixelWidth, image.PixelHeight), pixelsResult,
                              image.BackBufferStride, 0);
            var handler_ = ProgressChangeEventHandler;
            if (handler_ != null)
                handler_(null, new ProgressValueEventArgs(0));
        }

        // собель. Квадратный корень.
        public static void SobelSquareRoot(WriteableBitmap image)
        {
            var pixels = new byte[image.PixelHeight * image.BackBufferStride];
            var pixelsResult = new byte[image.PixelHeight * image.BackBufferStride];
            image.CopyPixels(pixels, image.BackBufferStride, 0);
            image.CopyPixels(pixelsResult, image.BackBufferStride, 0);
            for (var i = 0; i < image.PixelHeight - 2; i++)
            {
                var handler = ProgressChangeEventHandler;
                if (handler != null)
                    handler(null, new ProgressValueEventArgs((double)i / (double)(image.PixelHeight - 1)));
                for (var j = 0; j < image.PixelWidth - 2; j++)
                {
                    var r1 = pixels[i * image.PixelWidth * Plen + j * Plen] - pixels[i * image.PixelWidth * Plen + (j + 2) * Plen] +
                             2*(pixels[(i + 1) * image.PixelWidth * Plen + j * Plen] - pixels[(i + 1) * image.PixelWidth * Plen + (j + 2) * Plen]) +
                             pixels[(i + 2) * image.PixelWidth * Plen + j * Plen] - pixels[(i + 2) * image.PixelWidth * Plen + (j + 2) * Plen];
                    r1 *= r1;
                    var r2 = pixels[i * image.PixelWidth * Plen + j * Plen] - pixels[(i + 2) * image.PixelWidth * Plen + j * Plen] +
                             2*(pixels[i * image.PixelWidth * Plen + (j + 1) * Plen] - pixels[(i + 2) * image.PixelWidth * Plen + (j + 1) * Plen]) +
                             pixels[i * image.PixelWidth * Plen + (j + 2) * Plen] - pixels[(i + 2) * image.PixelWidth * Plen + (j + 2) * Plen];
                    r2 *= r2;
                    pixelsResult[i * image.PixelWidth * Plen + j * Plen] = (byte)Math.Max(0, Math.Min(255, Math.Sqrt(r1 + r2)));

                    var g1 = pixels[i * image.PixelWidth * Plen + j * Plen + 1] - pixels[i * image.PixelWidth * Plen + (j + 2) * Plen + 1] +
                             2*(pixels[(i + 1) * image.PixelWidth * Plen + j * Plen + 1] - pixels[(i + 1) * image.PixelWidth * Plen + (j + 2) * Plen + 1]) +
                             pixels[(i + 2) * image.PixelWidth * Plen + j * Plen + 1] - pixels[(i + 2) * image.PixelWidth * Plen + (j + 2) * Plen + 1];
                    g1 *= g1;
                    var g2 = pixels[i * image.PixelWidth * Plen + j * Plen + 1] - pixels[(i + 2) * image.PixelWidth * Plen + j * Plen + 1] +
                             2*(pixels[i * image.PixelWidth * Plen + (j + 1) * Plen + 1] - pixels[(i + 2) * image.PixelWidth * Plen + (j + 1) * Plen + 1]) +
                             pixels[i * image.PixelWidth * Plen + (j + 2) * Plen + 1] - pixels[(i + 2) * image.PixelWidth * Plen + (j + 2) * Plen + 1];
                    g2 *= g2;
                    pixelsResult[i * image.PixelWidth * Plen + j * Plen + 1] = (byte)Math.Max(0, Math.Min(255, Math.Sqrt(g1 + g2)));

                    var b1 = pixels[i * image.PixelWidth * Plen + j * Plen + 2] - pixels[i * image.PixelWidth * Plen + (j + 2) * Plen + 2] +
                             2*(pixels[(i + 1) * image.PixelWidth * Plen + j * Plen + 2] - pixels[(i + 1) * image.PixelWidth * Plen + (j + 2) * Plen + 2]) +
                             pixels[(i + 2) * image.PixelWidth * Plen + j * Plen + 2] - pixels[(i + 2) * image.PixelWidth * Plen + (j + 2) * Plen + 2];
                    b1 *= b1;
                    var b2 = pixels[i * image.PixelWidth * Plen + j * Plen + 2] - pixels[(i + 2) * image.PixelWidth * Plen + j * Plen + 2] +
                             2*(pixels[i * image.PixelWidth * Plen + (j + 1) * Plen + 2] - pixels[(i + 2) * image.PixelWidth * Plen + (j + 1) * Plen + 2]) +
                             pixels[i * image.PixelWidth * Plen + (j + 2) * Plen + 2] - pixels[(i + 2) * image.PixelWidth * Plen + (j + 2) * Plen + 2];
                    b2 *= b2;
                    pixelsResult[i * image.PixelWidth * Plen + j * Plen + 2] = (byte)Math.Max(0, Math.Min(255, Math.Sqrt(b1 + b2)));
                }
            }
            image.WritePixels(new System.Windows.Int32Rect(0, 0, image.PixelWidth, image.PixelHeight), pixelsResult,
                              image.BackBufferStride, 0);
            var handler_ = ProgressChangeEventHandler;
            if (handler_ != null)
                handler_(null, new ProgressValueEventArgs(0));
        }


        // Собель. Модуль.
        public static void SobelModule(WriteableBitmap image)
        {
            var pixels = new byte[image.PixelHeight * image.BackBufferStride];
            var pixelsResult = new byte[image.PixelHeight * image.BackBufferStride];
            image.CopyPixels(pixels, image.BackBufferStride, 0);
            image.CopyPixels(pixelsResult, image.BackBufferStride, 0);
            for (var i = 0; i < image.PixelHeight - 2; i++)
            {
                var handler = ProgressChangeEventHandler;
                if (handler != null)
                    handler(null, new ProgressValueEventArgs((double)i / (double)(image.PixelHeight - 1)));
                for (var j = 0; j < image.PixelWidth - 2; j++)
                {
                    var r1 = pixels[i * image.PixelWidth * Plen + j * Plen] - pixels[i * image.PixelWidth * Plen + (j + 2) * Plen] +
                             2*(pixels[(i + 1) * image.PixelWidth * Plen + j * Plen] - pixels[(i + 1) * image.PixelWidth * Plen + (j + 2) * Plen]) +
                             pixels[(i + 2) * image.PixelWidth * Plen + j * Plen] - pixels[(i + 2) * image.PixelWidth * Plen + (j + 2) * Plen];
                    r1 *= Math.Sign(r1);
                    var r2 = pixels[i * image.PixelWidth * Plen + j * Plen] - pixels[(i + 2) * image.PixelWidth * Plen + j * Plen] +
                             2*(pixels[i * image.PixelWidth * Plen + (j + 1) * Plen] - pixels[(i + 2) * image.PixelWidth * Plen + (j + 1) * Plen] )+
                             pixels[i * image.PixelWidth * Plen + (j + 2) * Plen] - pixels[(i + 2) * image.PixelWidth * Plen + (j + 2) * Plen];
                    r2 *= Math.Sign(r2);
                    pixelsResult[i * image.PixelWidth * Plen + j * Plen] = (byte)Math.Max(0, Math.Min(255, Math.Sqrt(r1 + r2)));

                    var g1 = pixels[i * image.PixelWidth * Plen + j * Plen + 1] - pixels[i * image.PixelWidth * Plen + (j + 2) * Plen + 1] +
                             2*(pixels[(i + 1) * image.PixelWidth * Plen + j * Plen + 1] - pixels[(i + 1) * image.PixelWidth * Plen + (j + 2) * Plen + 1]) +
                             pixels[(i + 2) * image.PixelWidth * Plen + j * Plen + 1] - pixels[(i + 2) * image.PixelWidth * Plen + (j + 2) * Plen + 1];
                    g1 *= Math.Sign(g1);
                    var g2 = pixels[i * image.PixelWidth * Plen + j * Plen + 1] - pixels[(i + 2) * image.PixelWidth * Plen + j * Plen + 1] +
                             2*(pixels[i * image.PixelWidth * Plen + (j + 1) * Plen + 1] - pixels[(i + 2) * image.PixelWidth * Plen + (j + 1) * Plen + 1] )+
                             pixels[i * image.PixelWidth * Plen + (j + 2) * Plen + 1] - pixels[(i + 2) * image.PixelWidth * Plen + (j + 2) * Plen + 1];
                    g2 *= Math.Sign(g2);
                    pixelsResult[i * image.PixelWidth * Plen + j * Plen + 1] = (byte)Math.Max(0, Math.Min(255, Math.Sqrt(g1 + g2)));

                    var b1 = pixels[i * image.PixelWidth * Plen + j * Plen + 2] - pixels[i * image.PixelWidth * Plen + (j + 2) * Plen + 2] +
                             2*(pixels[(i + 1) * image.PixelWidth * Plen + j * Plen + 2] - pixels[(i + 1) * image.PixelWidth * Plen + (j + 2) * Plen + 2]) +
                             pixels[(i + 2) * image.PixelWidth * Plen + j * Plen + 2] - pixels[(i + 2) * image.PixelWidth * Plen + (j + 2) * Plen + 2];
                    b1 *= Math.Sign(b1);
                    var b2 = pixels[i * image.PixelWidth * Plen + j * Plen + 2] - pixels[(i + 2) * image.PixelWidth * Plen + j * Plen + 2] +
                             2*(pixels[i * image.PixelWidth * Plen + (j + 1) * Plen + 2] - pixels[(i + 2) * image.PixelWidth * Plen + (j + 1) * Plen + 2] )+
                             pixels[i * image.PixelWidth * Plen + (j + 2) * Plen + 2] - pixels[(i + 2) * image.PixelWidth * Plen + (j + 2) * Plen + 2];
                    b2 *= Math.Sign(b2);
                    pixelsResult[i * image.PixelWidth * Plen + j * Plen + 2] = (byte)Math.Max(0, Math.Min(255, Math.Sqrt(b1 + b2)));
                }
            }
            image.WritePixels(new System.Windows.Int32Rect(0, 0, image.PixelWidth, image.PixelHeight), pixelsResult,
                              image.BackBufferStride, 0);
            var handler_ = ProgressChangeEventHandler;
            if (handler_ != null)
                handler_(null, new ProgressValueEventArgs(0));
        }
    }
}
